package com.easygroup.ngarihealth.plugin

import com.android.build.api.transform.JarInput

import java.security.MessageDigest
import java.util.jar.JarEntry
import java.util.jar.JarFile
import java.util.zip.ZipEntry
import java.util.zip.ZipOutputStream

/**
 * Created by fuxiaohua on 2021/5/10 0010.
 */
class Utils {

    private static String getMessageDigest(byte[] buffer) {
        MessageDigest mdTemp = MessageDigest.getInstance("MD5")
        mdTemp.update(buffer)
        byte[] digest = mdTemp.digest()
        StringBuffer sb = new StringBuffer()
        for (byte b : digest) {
            sb.append(String.format("%02x", b & 0xff))
        }
        return sb.toString()
    }

    static String getJarHexName(JarInput jarInput, boolean diffJar) {
        String destName = jarInput.name
        if (diffJar) {
            def hexName = getMessageDigest(jarInput.file.path.bytes)
            if (destName.endsWith(".jar")) {
                destName = destName.substring(0, destName.length() - 4)
            }
            return "$destName-$hexName"
        }
        return destName.substring(0, destName.length() - 4)
    }

    static byte[] readBytes(InputStream inputStream) throws Exception {
        def bos = new ByteArrayOutputStream()
        byte[] buffer = new byte[8196]
        int len
        while ((len = inputStream.read(buffer)) != -1) {
            bos.write(buffer, 0, len)
        }
        bos.close()
        inputStream.close()
        return bos.toByteArray()
    }

    /**
     * 将该jar包解压到指定目录
     * @param jarPath jar包的绝对路径
     * @param destDirPath jar包解压后的保存路径
     * @return 返回该jar包中包含的所有class的完整类名类名集合，其中一条数据如：com.aitski.hotpatch.Xxxx.class
     */
    static List<String> unzipJar(String jarPath, String destDirPath) {
        List<String> list = new ArrayList()
        if (jarPath.endsWith('.jar')) {
            JarFile jarFile = new JarFile(jarPath)
            Enumeration<JarEntry> entries = jarFile.entries()
            while (entries.hasMoreElements()) {
                JarEntry jarEntry = entries.nextElement()
                if (jarEntry.directory) {
                    continue
                }
                String entryName = jarEntry.getName()
                if (entryName.endsWith('.class')) {
                    String className = entryName.replaceAll("\\\\", ".").replaceAll("/", ".")
                    list.add(className)
                }
                String outFileName = destDirPath + "/" + entryName
                File outFile = new File(outFileName)
                outFile.getParentFile().mkdirs()
                InputStream inputStream = jarFile.getInputStream(jarEntry)
                FileOutputStream fileOutputStream = new FileOutputStream(outFile)
                fileOutputStream << inputStream
                fileOutputStream.close()
                inputStream.close()
            }
            jarFile.close()
        }
        return list
    }

    static void zipJar(File dirIn, File jarOut, HashMap<String, JarEntry> jarEntryHashMap) throws IOException {
        ZipOutputStream zos = null
        String packagePath = dirIn.absolutePath
        try {
            zos = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(jarOut)))
            Map<String, Integer> processedEntryNamesMap = new HashMap<>()
            dirIn.eachFileRecurse { File f ->
                String entryName = f.getAbsolutePath().substring(packagePath.length() + 1)
                if (processedEntryNamesMap.containsKey(entryName)) {
                    return
                }
                if (!f.directory) {
                    entryName = entryName.replaceAll("\\\\", "/")
                    ZipEntry entryOut = new ZipEntry(jarEntryHashMap.get(entryName))
                    entryOut.setCompressedSize(-1)
                    zos.putNextEntry(entryOut)
                    InputStream inputStream = null
                    try {
                        inputStream = new FileInputStream(f)
                        zos << inputStream
                    } finally {
                        closeQuietly(inputStream)
                        zos.closeEntry()
                    }
                    processedEntryNamesMap.put(entryName, 1)
                }
            }
        } finally {
            closeQuietly(zos)
        }
    }

    private static void closeQuietly(Closeable target) {
        if (target != null) {
            try {
                target.close()
            } catch (Exception ignored) {
                // Ignored.
            }
        }
    }
}
